/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.test;

import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.types.Binary;
import org.bson.types.ObjectId;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@SpringBootTest
public class GridFsTest {

    @Autowired
    @Qualifier("secondaryMongoTemplate")
    private MongoTemplate secondaryMongoTemplate;

    /**
     * 导出 GridFS 文件数据到本地 JSON 文件
     *
     * @param taskId    任务ID
     * @param exportDir 导出目录路径
     * @return 导出结果消息
     */
    public String exportGridFsData(String taskId, String exportDir) throws Exception {
        try {
            // 创建导出目录
            java.nio.file.Path exportPath = Paths.get(exportDir);
            Files.createDirectories(exportPath);

            // 查询 fs.files 集合
            List<Document> files = secondaryMongoTemplate.getCollection("fs.files")
                .find(new Document("metadata.taskId", taskId))
                .into(new ArrayList<>());

            if (files.isEmpty()) {
                return "未找到任务ID为 " + taskId + " 的文件";
            }

            // 提取所有文件的 ObjectId
            List<ObjectId> fileIds = new ArrayList<>();
            for (Document file : files) {
                fileIds.add(file.getObjectId("_id"));
            }

            // 查询 fs.chunks 集合
            List<Document> chunks = secondaryMongoTemplate.getCollection("fs.chunks")
                .find(new Document("files_id", new Document("$in", fileIds)))
                .into(new ArrayList<>());

            // 将 fs.files 数据写入 JSON 文件
            String filesJsonPath = exportPath.resolve("fs_files.json").toString();
            try (FileWriter writer = new FileWriter(filesJsonPath)) {
                JSONArray jsonArray = new JSONArray();
                for (Document file : files) {
                    jsonArray.put(DocumentToJsonObject(file));
                }
                writer.write(jsonArray.toString(4));
            }

            // 将 fs.chunks 数据写入 JSON 文件
            String chunksJsonPath = exportPath.resolve("fs_chunks.json").toString();
            try (FileWriter writer = new FileWriter(chunksJsonPath)) {
                JSONArray jsonArray = new JSONArray();
                for (Document chunk : chunks) {
                    jsonArray.put(DocumentToJsonObject(chunk));
                }
                writer.write(jsonArray.toString(4));
            }

            return String.format("成功导出 %d 个文件数据和 %d 个块数据到目录 %s",
                files.size(), chunks.size(), exportDir);
        } catch (IOException e) {
            log.error("导出 GridFS 数据失败", e);
            throw new RuntimeException("导出 GridFS 数据失败: " + e.getMessage(), e);
        }
    }

    /**
     * 增强的导出方法（确保 Base64 数据正确）
     */
    private JSONObject DocumentToJsonObject(Document doc) throws Exception {
        JSONObject json = new JSONObject();
        for (String key : doc.keySet()) {
            Object value = doc.get(key);

            if (value instanceof Binary) {
                // 处理 Binary 类型（之前的代码）
                Binary binaryData = (Binary) value;
                byte[] data = binaryData.getData();
                String base64String = Base64.getEncoder().encodeToString(data);
                json.put(key, base64String);

            } else if (value instanceof ObjectId) {
                json.put(key, ((ObjectId) value).toHexString());

            } else if (value instanceof Date) {
                // 正确处理日期类型：存储为时间戳或 ISO 格式字符串
                Date date = (Date) value;
                // 方案1：存储为时间戳（数字）
                json.put(key, date.getTime());

                // 方案2：存储为 ISO 格式字符串（更易读）
                // SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                // isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                // json.put(key, isoFormat.format(date));

            } else if (value instanceof Document) {
                json.put(key, DocumentToJsonObject((Document) value));

            } else {
                json.put(key, value);
            }
        }
        return json;
    }


    public String importGridFsData(String importDir, String targetTaskId) throws Exception {
        try {
            java.nio.file.Path importPath = Paths.get(importDir);

            // 读取 fs.files JSON 文件
            String filesJsonContent = new String(Files.readAllBytes(importPath.resolve("fs_files.json")));
            JSONArray filesArray = new JSONArray(filesJsonContent);

            // 读取 fs.chunks JSON 文件
            String chunksJsonContent = new String(Files.readAllBytes(importPath.resolve("fs_chunks.json")));
            JSONArray chunksArray = new JSONArray(chunksJsonContent);

            // 导入 fs.files 数据
            int filesImported = 0;
            MongoCollection<Document> filesCollection = secondaryMongoTemplate.getCollection("fs.files");
            for (int i = 0; i < filesArray.length(); i++) {
                JSONObject fileJson = filesArray.getJSONObject(i);
                Document fileDoc = jsonObjectToDocument(fileJson);

                // 更新任务ID（如果提供了新值）
                if (targetTaskId != null && !targetTaskId.isEmpty()) {
                    Document metadata = fileDoc.get("metadata", Document.class);
                    if (metadata != null) {
                        metadata.put("taskId", targetTaskId);
                        fileDoc.put("metadata", metadata);
                    }
                }

                // 插入或更新文件数据
                filesCollection.replaceOne(
                    new Document("_id", fileDoc.getObjectId("_id")),
                    fileDoc,
                    new com.mongodb.client.model.ReplaceOptions().upsert(true)
                );
                filesImported++;
            }

            // 导入 fs.chunks 数据
            int chunksImported = 0;
            MongoCollection<Document> chunksCollection = secondaryMongoTemplate.getCollection("fs.chunks");
            for (int i = 0; i < chunksArray.length(); i++) {
                JSONObject chunkJson = chunksArray.getJSONObject(i);
                Document chunkDoc = jsonObjectToDocument(chunkJson);

                // 插入或更新块数据
                chunksCollection.replaceOne(
                    new Document("_id", chunkDoc.getObjectId("_id")),
                    chunkDoc,
                    new com.mongodb.client.model.ReplaceOptions().upsert(true)
                );
                chunksImported++;
            }

            return String.format("成功导入 %d 个文件数据和 %d 个块数据", filesImported, chunksImported);
        } catch (IOException e) {
            log.error("导入 GridFS 数据失败", e);
            throw new RuntimeException("导入 GridFS 数据失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将 JSONObject 转换为 MongoDB Document
     */
    private Document jsonObjectToDocument(JSONObject json) throws Exception {
        Document doc = new Document();
        Iterator<String> keys = json.keys();

        while (keys.hasNext()) {
            String key = keys.next();
            Object value = json.get(key);

            try {
                if (value instanceof JSONObject) {
                    doc.put(key, jsonObjectToDocument((JSONObject) value));

                } else if ("_id".equals(key) && value instanceof String) {
                    doc.put(key, new ObjectId((String) value));

                } else if ("files_id".equals(key) && value instanceof String) {
                    doc.put(key, new ObjectId((String) value));

                } else if ("uploadDate".equals(key) || key.endsWith("Date") || key.endsWith("date")) {
                    // 处理日期字段
                    if (value instanceof Number) {
                        // 从时间戳创建 Date
                        long timestamp = ((Number) value).longValue();
                        doc.put(key, new Date(timestamp));
                    } else if (value instanceof String) {
                        // 尝试从字符串解析日期
                        try {
                            // 如果是时间戳字符串
                            long timestamp = Long.parseLong((String) value);
                            doc.put(key, new Date(timestamp));
                        } catch (NumberFormatException e) {
                            // 如果是 ISO 格式字符串
                            try {
                                SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                                isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                                Date date = isoFormat.parse((String) value);
                                doc.put(key, date);
                            } catch (ParseException ex) {
                                // 如果无法解析，保持原始值
                                doc.put(key, value);
                            }
                        }
                    } else {
                        doc.put(key, value);
                    }

                } else if ("data".equals(key) && value instanceof String) {
                    doc.put(key, parseBinaryData((String) value));

                } else {
                    doc.put(key, value);
                }
            } catch (Exception e) {
                System.err.println("处理字段 '" + key + "' 时出错: " + e.getMessage());
                doc.put(key, value);
            }
        }
        return doc;
    }

    /**
     * 解析 Binary 数据字符串（支持多种格式）
     */
    private Binary parseBinaryData(String dataString) {
        try {
            // 先尝试清理字符串（移除可能的多余字符）
            String cleanedString = cleanBase64String(dataString);

            // 尝试直接解码（如果是纯 Base64）
            try {
                byte[] decodedBytes = Base64.getDecoder().decode(cleanedString);
                return new Binary(decodedBytes);
            } catch (IllegalArgumentException e) {
                // 如果不是纯 Base64，尝试解析 Binary("...", ...) 格式
                return parseBinaryFormatString(dataString);
            }
        } catch (Exception e) {
            System.err.println("解析 Binary 数据失败: " + dataString);
            throw new RuntimeException("无法解析 Binary 数据: " + e.getMessage(), e);
        }
    }

    /**
     * 解析 Binary("base64string", type) 格式的字符串
     */
    private Binary parseBinaryFormatString(String binaryString) {
        // 匹配 Binary("base64string", type) 格式
        Pattern pattern = Pattern.compile("Binary\\(\"([^\"]+)\",\\s*(\\d+)\\)");
        Matcher matcher = pattern.matcher(binaryString);

        if (matcher.find()) {
            String base64Data = matcher.group(1);
            // 清理 Base64 字符串
            String cleanedBase64 = cleanBase64String(base64Data);
            byte[] decodedBytes = Base64.getDecoder().decode(cleanedBase64);
            return new Binary(decodedBytes);
        }

        throw new IllegalArgumentException("无法识别的 Binary 格式: " + binaryString);
    }

    /**
     * 清理 Base64 字符串（移除非法字符）
     */
    private String cleanBase64String(String base64String) {
        // 移除可能的多余字符（控制字符、空格等）
        return base64String.replaceAll("[^a-zA-Z0-9+/=]", "");
    }

    @Test
    public void test() throws Exception {


//        fixCorruptedDateFields("241");

        // 导出数据
//        String exportResult = exportGridFsData("241", "/path/to/export");
//        System.out.println(exportResult);

        // 导入数据到新的任务ID
        String importResult = importGridFsData("D:\\要素库项目\\二期\\载荷库\\数据\\path\\to\\export", "241");
        System.out.println(importResult);
    }


    /**
     * 修复 MongoDB 中损坏的日期字段
     */
    public void fixCorruptedDateFields(String taskId) {
        // 查找所有 uploadDate 字段为字符串的文档
        BasicDBObject query = new BasicDBObject("metadata.taskId", taskId)
            .append("uploadDate", new BasicDBObject("$type", "string"));

        MongoCollection<Document> filesCollection = secondaryMongoTemplate.getCollection("fs.files");
        MongoCursor<Document> cursor = filesCollection.find(query).iterator();

        int fixedCount = 0;
        while (cursor.hasNext()) {
            Document fileDoc = cursor.next();
            Object uploadDateValue = fileDoc.get("uploadDate");

            if (uploadDateValue instanceof String) {
                try {
                    String dateString = (String) uploadDateValue;
                    // 尝试解析日期字符串
                    Date parsedDate;

                    if (dateString.matches("\\d+")) {
                        // 如果是时间戳字符串
                        parsedDate = new Date(Long.parseLong(dateString));
                    } else {
                        // 尝试解析 ISO 格式
                        SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                        isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                        parsedDate = isoFormat.parse(dateString);
                    }

                    // 更新文档
                    filesCollection.updateOne(
                        new Document("_id", fileDoc.getObjectId("_id")),
                        new Document("$set", new Document("uploadDate", parsedDate))
                    );
                    fixedCount++;

                } catch (Exception e) {
                    System.err.println("无法修复文档 " + fileDoc.getObjectId("_id") + " 的日期字段: " + e.getMessage());
                }
            }
        }
        System.out.println("修复了 " + fixedCount + " 个损坏的日期字段");
    }
}
